package gui.product;

import gui.common.Controller;
import gui.common.IView;
import gui.common.SizeUnits;
import model.entity.Product;
import model.management.ProductManager;
import productidentification.IProductIdentifier;
import productidentification.ProductIdentifierFactory;

import common.Barcode;
import common.Size;
import common.StringOps;

/**
 * Controller class for the add item view.
 */
public class AddProductController extends Controller implements IAddProductController
{
  private final String code;

  private boolean      requestingData;

  /**
   * Constructor.
   * 
   * @param view
   *          Reference to the add product view
   * @param barcode
   *          Barcode for the product being added
   */
  public AddProductController(IView view, String barcode)
  {
    super(view);

    code = barcode;
    requestingData = true;

    construct();
  }

  //
  // Controller overrides
  //

  /**
   * Returns a reference to the view for this controller.
   * 
   * {@pre None}
   * 
   * {@post Returns a reference to the view for this controller.}
   */
  @Override
  protected IAddProductView getView()
  {
    return (IAddProductView) super.getView();
  }

  /**
   * Sets the enable/disable state of all components in the controller's view. A component should
   * be enabled only if the user is currently allowed to interact with that component.
   * 
   * {@pre None}
   * 
   * {@post The enable/disable state of all components in the controller's view have been set
   * appropriately.}
   */
  @Override
  protected void enableComponents()
  {
    getView().enableBarcode(false);

    try
    {
      float amount = Float.parseFloat(getView().getSizeValue());
      if (amount <= 0f)
        throw new Exception();

      if (amount != 1f && getView().getSizeUnit().equals(SizeUnits.Count))
        throw new Exception();

      int supply = Integer.parseInt(getView().getSupply());
      if (supply < 0)
        throw new Exception();

      int life = Integer.parseInt(getView().getShelfLife());
      if (life < 0)
        throw new Exception();

      String description = getView().getDescription();
      if (StringOps.isNullOrEmpty(description))
        throw new Exception();

      if (requestingData)
        throw new Exception();

      getView().enableOK(true);
    }
    catch (Exception e)
    {
      getView().enableOK(false);
    }

    getView().enableSizeValue(getView().getSizeUnit() != SizeUnits.Count);
  }

  private Product generateProduct()
  {
    try
    {
      Barcode barcode = new Barcode(code);
      String description = getView().getDescription();
      float amount = Float.parseFloat(getView().getSizeValue());
      Size size = new Size(amount, getView().getSizeUnit());
      int shelfLife = Integer.parseInt(getView().getShelfLife());
      int supply = Integer.parseInt(getView().getSupply());

      return new Product(barcode, description, size, shelfLife, supply);
    }
    catch (Exception e)
    {
      return null;
    }
  }

  private void forceComponentsEnabled(boolean enable)
  {
    getView().enableDescription(enable);
    getView().enableOK(enable);
    getView().enableShelfLife(enable);
    getView().enableSizeUnit(enable);
    getView().enableSizeValue(enable);
    getView().enableSupply(enable);
  }

  /**
   * Loads data into the controller's view.
   * 
   * {@pre None}
   * 
   * {@post The controller has loaded data into its view}
   */
  @Override
  protected void loadValues()
  {
    getView().setBarcode(code);
    getView().setSizeValue("1");
    getView().setShelfLife("0");
    getView().setSupply("0");

    // Get product description from web service
    forceComponentsEnabled(false);
    requestingData = true;
    getView().setDescription("Identifying Product - Please Wait");
    new Thread()
    {
      @Override
      public void run()
      {
        try
        {
          // This method will return null if no plugins were found.
          IProductIdentifier identifier = ProductIdentifierFactory.getProductIdentifier();
          String description = identifier.identifyProduct(code);
          getView().setDescription(description);
          if (StringOps.isNullOrEmpty(description))
            getView().enableDescription(true);
        }
        catch (Exception e)
        {
          getView().setDescription("");
        }
        finally
        {
          requestingData = false;
          forceComponentsEnabled(true);
          enableComponents();
        }
      }
    }.start();
  }

  //
  // IAddProductController overrides
  //

  /**
   * This method is called when any of the fields in the add product view is changed by the user.
   */
  @Override
  public void valuesChanged()
  {
    if (getView().getSizeUnit() == SizeUnits.Count)
      getView().setSizeValue("1");

    enableComponents();
  }

  /**
   * This method is called when the user clicks the "OK" button in the add product view.
   */
  @Override
  public void addProduct()
  {
    Product product = generateProduct();
    ProductManager.addProduct(product);
  }
}
